package pizza.util;
/** an abstract class for implementations of the Enumeration interface
*/
public abstract class Enumerator implements Enumeration {
/** the Enumeration methods
*/
public abstract boolean hasMoreElements();
public abstract A nextElement();
/** concat another enumerator, to be called when this one is done
*/
public Enumerator concat(Enumerator rest) {
return new CompositeEnumerator(this, rest);
}
/** return enumerator that yields `f' applied to each element
* of this enumerator
*/
public Enumerator map((A)->B f) {
return new MapEnumerator(f, this);
}
/** return elements of this enumerator as long as predicate `p' is true
*/
public Enumerator takeWhile((A)->boolean p) {
return new TakeWhileEnumerator(p, this);
}
/** return enumerator that starts with the first element of this
* enumerator for which `p' holds, and then continues with all
* subsequent elements of this enumerator
*/
public Enumerator dropWhile((A)->boolean p) {
return new DropWhileEnumerator(p, this);
}
/** return enumerator that yields all element of this enumerator that
* satisfy predicate `p'.
*/
public Enumerator filter((A)->boolean p) {
return new FilterEnumerator(p, this);
}
/** apply function `f' to all elements of this enumerator
*/
public void forall((A)->B f) {
while (hasMoreElements()) f(nextElement());
}
/** reduce all elements of this enumerator with binary operation `f',
* starting with `z'. Operations are grouped to the left.
*/
public B reduceLeft(B z, (B,A)->B f) {
while (hasMoreElements()) z = f(z, nextElement());
return z;
}
/** reduce all elements of this enumerator with binary operation `f',
* starting with `z'. Operations are grouped to the right.
*/
public B reduceRight((A,B)->B f, B z) {
if (hasMoreElements()) return f(nextElement(), reduceRight(f, z));
else return z;
}
}
/** an enumerator implementing `map'
*/
class MapEnumerator extends Enumerator {
private (B)->A f;
private Enumerator dom;
MapEnumerator((B)->A f, Enumerator dom) {
this.f = f;
this.dom = dom;
}
public boolean hasMoreElements() {
return dom.hasMoreElements();
}
public A nextElement() {
return f(dom.nextElement());
}
}
/** an enumerator implementing `filter'
*/
class FilterEnumerator extends Enumerator {
private (A)->boolean p;
private Enumerator dom;
private A next;
private boolean lookahead;
FilterEnumerator((A)->boolean p, Enumerator dom) {
this.p = p;
this.dom = dom;
lookahead = false;
}
public boolean hasMoreElements() {
while (!lookahead && dom.hasMoreElements()) {
next = dom.nextElement();
lookahead = p(next);
}
return lookahead;
}
public A nextElement() {
if (lookahead || hasMoreElements()) {
lookahead = false;
return next;
}
throw new NoSuchElementException();
}
}
/** an enumerator implementing `takewhile'
*/
class TakeWhileEnumerator extends Enumerator {
private (A)->boolean p;
private Enumerator dom;
private A next;
private boolean lookahead;
TakeWhileEnumerator((A)->boolean p, Enumerator dom) {
this.p = p;
this.dom = dom;
lookahead = false;
}
public boolean hasMoreElements() {
if (!lookahead && dom.hasMoreElements()) {
next = dom.nextElement();
if (p(next)) lookahead = true;
else dom = EmptyEnumerator.empty;
}
return lookahead;
}
public A nextElement() {
if (lookahead || hasMoreElements()) {
lookahead = false;
return next;
}
throw new NoSuchElementException();
}
}
/** an enumerator implementing `dropwhile'
*/
class DropWhileEnumerator extends Enumerator {
private (A)->boolean p;
private Enumerator dom;
private A next;
private boolean lookahead;
DropWhileEnumerator((A)->boolean p, Enumerator dom) {
this.p = p;
this.dom = dom;
lookahead = false;
}
public boolean hasMoreElements() {
while (p != null && dom.hasMoreElements()) {
next = dom.nextElement();
if (!p(next)) {
lookahead = true;
p = null;
}
}
return lookahead || dom.hasMoreElements();
}
public A nextElement() {
if (lookahead || p != null && hasMoreElements()) {
lookahead = false;
return next;
} else {
return dom.nextElement();
}
}
}